import { NestApplication, NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import {
  ValidationPipe,
  BadRequestException,
  VersioningType,
} from '@nestjs/common';
import { Logger } from './common/logger/logger';
import chalk from 'chalk';
import session from 'express-session';
import { HttpExceptionFilter } from './core/filter/http-exception/http-exception.filter';
import { TransformInterceptor } from './core/interceptor/transform/transform.interceptor';

async function bootstrap() {
  const app = await NestFactory.create<NestApplication>(AppModule, {
    cors: true,
    logger: ['error', 'warn'],
  });

  // 配置session (测试session)
  app.use(
    session({
      secret: 'ssh-secret-key',
      cookie: {
        httpOnly: true,
        path: '/',
        maxAge: 1000 * 60 * 5, // 5分钟过期
      },
      name: 'nest.sid', // chrome中 保存session的cookie key 。默认是 connect.sid
      resave: false, // 每次访问都会更新 session，不管有没有修改 session 的内容，而 false 是只有 session 内容变了才会去更新 session
      saveUninitialized: false, // 不管是否设置 session，都会初始化一个空的 session 对象
    }),
  );

  const config = app.get(ConfigService);
  const prefix = config.get<string>('API_PREFIX');

  if (!prefix) {
    throw new Error('API_PREFIX is not defined');
  }

  // 全局接口前缀
  app.setGlobalPrefix(prefix);

  // 全局日志
  app.useLogger(app.get(Logger));

  // 全局接口正常响应拦截器
  app.useGlobalInterceptors(new TransformInterceptor(app.get(Logger)));
  // 全局接口异常过滤器
  app.useGlobalFilters(new HttpExceptionFilter(app.get(Logger)));

  // 增强的全局验证管道 ，用于验证class-validator 提供的功能
  app.useGlobalPipes(
    new ValidationPipe({
      // 自动将请求数据转换为DTO类的实例
      transform: true,
      // 自动过滤掉DTO中未定义的属性
      whitelist: true,
      //如果请求中包含DTO未定义的字段，会直接返回400错误。当whitelist forbidNonWhitelisted 两个选项同时启用时，
      //系统的行为是： 先检查是否有非白名单字段，如果有则直接返回400错误，而不是先过滤再继续处理 。
      forbidNonWhitelisted: true,
      exceptionFactory: (errors) => {
        const errorMessages = errors
          .map((error) => Object.values(error.constraints || {}).join(', '))
          .join('; ');
        console.error('Validation error:', errorMessages);
        return new BadRequestException(errorMessages);
      },
    }),
  );

  // 版本号可以通过在URL中添加版本号前缀来指定，例如：/api/v1/endpoint
  // 如果要兼容旧版本接口，可以配置@Version([VERSION_NEUTRAL, defaultVersion]) 来指定兼容的版本号
  const version = config.get<string>('API_VERSION');
  if (version) {
    app.enableVersioning({
      type: VersioningType.URI,
      defaultVersion: version,
      prefix: 'v',
    });
  }

  const port = config.get<number | string>('APP_PORT');
  if (!port) {
    throw new Error('APP_PORT is not defined');
  }

  console.log(
    chalk.magenta('current environment :'),
    chalk.green(process.env.NODE_ENV),
  );
  console.log(
    chalk.magenta('SERVER START SUCCEEDED : url->'),
    chalk.green(
      `http://127.0.0.1:${config.get<number>('APP_PORT')}${prefix}\n`,
    ),
  );

  // // 测试应用的生命周期函数
  // setTimeout(async () => {
  //   console.log('开始关闭应用...');
  //   await app.close();
  //   console.log('应用已关闭');
  // }, 5000);

  // 启动应用
  await app.listen(port);
}

void bootstrap();
